/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */
package xowl.gmi.controller;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Laurent WOUTERS
 */
public class GraphNode extends ASTElement implements xowl.gmi.view.diagram.GraphNode.Actions {
    protected xowl.gmi.model.cvssl.Node definition;
    protected xowl.gmi.view.diagram.GraphNode widget;
    protected Element child;
    protected List<GraphConnector> connectors;
    protected Integer obsXSet;
    protected Integer obsYSet;
    
    public xowl.gmi.model.cvssl.Node getDefinition() { return definition; }
    public xowl.gmi.view.diagram.GraphNode getVisual() { return widget; }
    public Integer getLayer() { return getDecorator().getIndex(); }
    public void addConnector(GraphConnector connector) { connectors.add(connector); }
    public void removeConnector(GraphConnector connector) { connectors.remove(connector); }
    
    public GraphNode(Controller controller, Element parent, xowl.gmi.model.cvssl.Node def, xowl.gmi.model.ast.ASTNode node) {
        super(controller, parent, node);
        this.definition = def;
        this.connectors = new ArrayList<>();
        xowl.gmi.model.ast.Decorator decorator = this.getDecorator();
        decorator.addPropertyObserver("positionX", new xowl.interpreter.adapter.DataPropertyObserver() {
            @Override public void onAdd(Object elem) {
                obsXSet = (Integer)elem;
                onPositionSet();
            }
            @Override public void onRemove(Object elem) { }
        });
        decorator.addPropertyObserver("positionY", new xowl.interpreter.adapter.DataPropertyObserver() {
            @Override public void onAdd(Object elem) {
                obsYSet = (Integer)elem;
                onPositionSet();
            }
            @Override public void onRemove(Object elem) { }
        });
        decorator.addPropertyObserver("index", new xowl.interpreter.adapter.DataPropertyObserver() {
            @Override public void onAdd(Object elem) { ((Graph)GraphNode.this.parent).onNodeChangedLayer(GraphNode.this, (Integer)elem); }
            @Override public void onRemove(Object elem) { }
        });

        this.widget = new xowl.gmi.view.diagram.GraphNode(this, controller.getLocale());
        if (decorator.getPositionX() != null)
            this.widget.setPosition(new xowl.gmi.view.diagram.Couple(decorator.getPositionX(), decorator.getPositionY()));
        setupExecution(widget);
    }
    
    public void setChild(Element child) {
        this.child = child;
        this.widget.setChild(child.getWidget());
    }
    
    @Override protected void onChildAdd(xowl.gmi.model.ast.ASTNode node) { child.insertAST(node); }
    @Override protected void onChildRemove(xowl.gmi.model.ast.ASTNode node) { child.removeAST(node); }
    
    @Override public xowl.gmi.view.diagram.Widget getWidget() { return widget; }

    @Override public void saveTo(xowl.gmi.model.Diagram diagram) {
        xowl.gmi.model.ast.Decorator decorator = getDecorator();
        String iri = this.getModelIRI().getHasValue();
        String piri = this.getASTParent().getModelIRI().getHasValue();
        diagram.addElement(new xowl.gmi.model.DiagramNode(piri, iri, decorator.getPositionX(), decorator.getPositionY(), decorator.getIndex()));
        child.saveTo(diagram);
    }
    @Override public void decommission() {
        this.decommissionListeners();
        child.decommission();
    }
    
    @Override public boolean isConnectionStart() { return controller.connectCanStartAt(this); }
    @Override public boolean isConnectionEnd() { return controller.connectCanEndAt(this); }
    @Override public void startConnection(int portID) { controller.connectStart(new GraphNodePort((Graph)parent, this, portID)); }
    @Override public void endConnection(int portID) { controller.connectEnd(new GraphNodePort((Graph)parent, this, portID)); }
    @Override public void onMenuLayerUp() { ((Graph)parent).actionNodeLayerUp(this); }
    @Override public void onMenuLayerDown() { ((Graph)parent).actionNodeLayerDown(this); }
    @Override public void onMenuLayerTop() { ((Graph)parent).actionNodeLayerTop(this); }
    @Override public void onMenuLayerBottom() { ((Graph)parent).actionNodeLayerBottom(this); }
    @Override public java.awt.datatransfer.DataFlavor getFlavor() { return Controller.flavorASTElementTO; }
    @Override public Object getTransferable(java.awt.Point dragPoint) { return new ASTElementTO(this, dragPoint); }
    
    private void onPositionSet() {
        if (obsXSet != null && obsYSet != null) {
            widget.moveTo(obsXSet, obsYSet);
            obsXSet = null;
            obsYSet = null;
            controller.onDiagramUpdated();
        }
    }
}
